package cn.wen.yinxiu.works.service.impl;

import cn.wen.yinxiu.common.base.holder.UserDTO;
import cn.wen.yinxiu.common.base.holder.UserHolder;
import cn.wen.yinxiu.common.cache.DistributedCache;
import cn.wen.yinxiu.common.constant.Constant;
import cn.wen.yinxiu.common.constant.RedisConstants;
import cn.wen.yinxiu.common.convention.result.ResultEntity;
import cn.wen.yinxiu.common.enums.DelEnum;
import cn.wen.yinxiu.common.enums.StatusEnum;
import cn.wen.yinxiu.common.to.es.SearchParamTO;
import cn.wen.yinxiu.common.to.es.WorksEsModel;
import cn.wen.yinxiu.common.to.system.AdvertTO;
import cn.wen.yinxiu.common.to.works.SimpleWorksTO;
import cn.wen.yinxiu.common.toolkit.*;
import cn.wen.yinxiu.common.vo.UserWithStatusReq;
import cn.wen.yinxiu.works.entity.*;
import cn.wen.yinxiu.works.feign.FileFeignService;
import cn.wen.yinxiu.works.feign.SearchFeignService;
import cn.wen.yinxiu.works.feign.SystemFeignService;
import cn.wen.yinxiu.works.feign.UserFeignService;
import cn.wen.yinxiu.works.recommend.IRecommend;
import cn.wen.yinxiu.works.service.*;
import cn.wen.yinxiu.works.to.HeaderNavUserInfoTO;
import cn.wen.yinxiu.works.to.UserDataInfo;
import cn.wen.yinxiu.works.vo.*;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.wen.yinxiu.works.dao.WorksDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import static cn.wen.yinxiu.common.constant.Constant.WorksType.Image;
import static cn.wen.yinxiu.common.constant.Constant.WorksType.Video;

@Slf4j
@Component
@Service("worksService")
public class WorksServiceImpl extends ServiceImpl<WorksDao, WorksEntity> implements WorksService {

    @Value("${yinxiu.pageSize}")
    private Integer pageSize;

    @Value("${yinxiu.serve.pageSize}")
    private Integer servePageSize;

    @Value("${yinxiu.recommend.pageSize}")
    private Integer recommendPageSize;

    @Autowired
    private WorksDao worksDao;

    @Autowired
    private UsersCollectRelationService collectService;

    @Autowired
    private UsersLikeRelationService likeService;

    @Autowired
    private VisitHistoryService visitHistoryService;

    @Autowired
    private ImagesService imagesService;

    @Autowired
    private VideosService videosService;

    @Autowired
    private IRecommend recommend;

    @Autowired
    private TopicService topicService;

    @Autowired
    private WorksDataService worksDataService;

    @Autowired
    private FileFeignService fileFeignService;

    @Autowired
    private UserFeignService userFeignService;

    @Autowired
    private DistributedCache distributedCache;

    @Autowired
    private WeekReportService weekReportService;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private SearchFeignService searchFeignService;

    @Autowired
    private SystemFeignService systemFeignService;

    @Autowired
    private AudioService audioService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WorksEntity> page = this.page(
                new Query<WorksEntity>().getPage(params),
                new QueryWrapper<WorksEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public Long queryWorksListCount(Long userId) {
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        return worksDao.selectCount(queryWrapper);
    }

    @Override
    public HeaderNavUserInfoTO queryWorksHeadNavCount(Long userId) {
        // TODO 使用线程池异步编程实现
        HeaderNavUserInfoTO target = new HeaderNavUserInfoTO();
        // 1.作品数量
        Long worksCount = queryWorksListCount(userId);
        target.setWorksCount(worksCount);
        // 2.用户收藏数量
        Long collectCount = collectService.queryUserCollectWorksCount(userId);
        target.setCollectCount(collectCount);
        // 3.用户浏览记录
        Long visitHistoryCount = visitHistoryService.queryUserVisitHistoryCount(userId);
        target.setVisitHistoryCount(visitHistoryCount);
        // 4.我的喜欢数量
        Long likeCount = likeService.queryUserLikeWorksCount(userId);
        target.setLikeCount(likeCount);
        return target;
    }

    @Override
    public List<WorksListInfo> queryWorksList(Long userId, String keyword, Integer page) {
        // 1.获取作品信息
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        if (StringUtils.isNotEmpty(keyword)) {
            queryWrapper.like("works_desc", keyword);
        }
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("LIMIT " + pageSize * (page - 1) + "," + pageSize);
        List<WorksEntity> worksList = worksDao.selectList(queryWrapper);
        // 2.通过作品信息来获取相对应的照片作品或者视频作品
        return worksEntToWorksInfo(worksList);
    }

    private List<WorksListInfo> worksEntToWorksInfo(List<WorksEntity> worksList) {
        List<WorksListInfo> list = new ArrayList<>();
        for (WorksEntity worksEntity : worksList) {
            WorksListInfo target = new WorksListInfo();
            target.setWorksId(worksEntity.getId());
            target.setWorksDesc(worksEntity.getWorksDesc());
            target.setWorksType(worksEntity.getWorksType());
            target.setLikeCounts(worksEntity.getLikeCounts());
            if (worksEntity.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
                target.setWorksSeconds(imagesEntity.getImageSeconds());
            } else if (worksEntity.getWorksType() == Video.getCode()) {
                VideosEntity videosEntity = videosService.getById(worksEntity.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
                target.setWorksSeconds(videosEntity.getVideoSeconds());
            }
            // 链表操作获取批量的TopicInfo列表
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
            target.setTopicList(topicList);
            list.add(target);
        }
        return list;
    }

    @Override
    public List<WorksListInfo> queryWorksLikeList(Long userId, Integer page, String keyword) {
        // 1.获取作品列表
        List<WorksEntity> worksList = worksDao.selectWorksLikeList(userId, keyword, pageSize * (page - 1),
                pageSize, StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        /// 2.通过作品信息来获取相对应的照片作品或者视频作品
        return worksEntToWorksInfo(worksList);
    }

    @Override
    public List<WorksListInfo> queryWorksCollectList(Long userId, Integer page) {
        // 1.获取作品列表
        List<WorksEntity> worksList = worksDao.selectWorksCollectList(userId, pageSize * (page - 1),
                pageSize, StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        /// 2.通过作品信息来获取相对应的照片作品或者视频作品
        return worksEntToWorksInfo(worksList);
    }

    @Override
    public List<WorksListInfo> queryWorksVisitHistoryList(Long userId, Integer page) {
        // 1.获取作品列表
        List<WorksEntity> worksList = worksDao.selectWorksVisitHistoryList(userId, pageSize * (page - 1),
                pageSize, StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        /// 2.通过作品信息来获取相对应的照片作品或者视频作品
        return worksEntToWorksInfo(worksList);
    }

    @Override
    public List<WorksVO> queryFriendWorksList(Long userId, Integer page) {

        return null;
    }

    @Override
    public List<WorksListInfo> queryWorksList(UserWithStatusReq req) {
        // 1.获取状态信息
        Integer status = req.getStatus();
        // 2.调用请求
        // 2.1.获取作品列表 如果status == -1 则全部查询
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", req.getUserId());
        if (status != -1) {
            queryWrapper.eq("status", status);
        }
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        if (StringUtils.isNotEmpty(req.getKeyword())) {
            queryWrapper.like("works_desc", req.getKeyword());
        }
        queryWrapper.orderByDesc("top").orderByDesc("update_time");
        queryWrapper.last("LIMIT " + pageSize * (req.getPage() - 1) + "," + servePageSize);
        List<WorksEntity> worksList = worksDao.selectList(queryWrapper);
        List<WorksListInfo> list = new ArrayList<>();
        for (WorksEntity worksEntity : worksList) {
            WorksListInfo target = new WorksListInfo();
            target.setWorksDesc(worksEntity.getWorksDesc());
            target.setWorksId(worksEntity.getId());
            target.setWorksType(worksEntity.getWorksType());
            target.setLikeCounts(worksEntity.getLikeCounts());
            target.setTop(worksEntity.isTop());
            target.setCollectCounts(worksEntity.getCollectCounts());
            target.setCommentCounts(worksEntity.getCommentCounts());
            target.setStatus(worksEntity.getStatus());
            target.setUpdateTime(worksEntity.getUpdateTime());
            if (worksEntity.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
                target.setWorksSeconds(imagesEntity.getImageSeconds());
            } else if (worksEntity.getWorksType() == Video.getCode()) {
                VideosEntity videosEntity = videosService.getById(worksEntity.getImageId());
                target.setCoverPath(videosEntity.getCoverPath());
                target.setWorksSeconds(videosEntity.getVideoSeconds());
            }
            // 链表操作获取批量的TopicInfo列表
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
            target.setTopicList(topicList);
            list.add(target);
        }
        return list;
    }

    @Override
    public boolean deleteWorksVisitHistory(Long userId) {
        // 1.校验当前用户是否为登录用户  通过token获取redis中的UserInfo比对ID
        UserDTO user = UserHolder.getUser();
        if (user.getUserId() != userId) return false;
        // 2.修改浏览记录状态 is_deleted 为true 7天会自动物理删除为true的记录
        return visitHistoryService.deleteWorksVisitHistory(userId);
    }

    @Override
    public ServeHomeInfo getServeHomeInfo(Long userId, Integer dayNum) {
        ServeHomeInfo target = new ServeHomeInfo();
        // 1.作品数据（增加量）使用Redis来实现添加量 (默认是每日00:00更新)
        CompletableFuture<Void> serveHomeFuture = CompletableFuture.runAsync(() -> {
            // 默认是 1 天的间隔 更新数据
            ServeHomeInfo data = worksDataService.getWorksDataByDay(userId, dayNum);
            BeanUtils.copyProperties(data, target, "twoWeekFiledWorksMap");
        }, executor);

        // 2.两周的上传作品量折线图
        CompletableFuture<Void> uploadWorksFuture = CompletableFuture.runAsync(() -> {
            Map<String, Object> worksMap = getTwoWeekUploadWorks(userId);
            target.setTwoWeekFiledWorksMap(worksMap);
        }, executor);
        // 等待所有任务完成
        try {
            CompletableFuture.allOf(serveHomeFuture, uploadWorksFuture).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return target;
    }

    @Transactional
    @Override
    public boolean addWorksInfo(MultipartFile[] fileList, String worksJson) {
        int res = 0;
        try {
            // 1.远程调用文件上传服务
            ResultEntity<String> fileRes = fileFeignService.uploadCloudFile(Arrays.asList(fileList));
            String worksPath = fileRes.getData();
            // 2.解析对应的JSON数据
            Gson gson = new Gson();
            AddWorksVO target = gson.fromJson(worksJson, AddWorksVO.class);
            // 3.根据对应的数据格式进行解析
            // 3.1.解析作品数据和封面图
            String coverPath = "";
            // 最后一个作为封面图
            if (StringUtils.isNotEmpty(worksPath)) {
                int idx = worksPath.lastIndexOf(';');
                coverPath = worksPath.substring(idx + 1);
                worksPath = worksPath.substring(0, idx);
            }
            // 3.2.话题ID topicIds
            String topicIdStr = target.getTopicTitleList();
            String[] split = topicIdStr.split(";");
            // 4.补充相关信息 根据作品类型存储记录
            UserDTO user = UserHolder.getUser();
            WorksEntity worksEntity = new WorksEntity();
            BeanUtils.copyProperties(target, worksEntity);
            worksEntity.setAuthorName(user.getUsername());
            worksEntity.setStatus(StatusEnum.WAITING_REVIEW.code());
            worksEntity.setTop(false);
            worksEntity.setIsDeleted(DelEnum.NORMAL.code());
            worksEntity.setUserAvatar(user.getAvatar());
            if (target.getWorksType() == Video.getCode()) {
                VideosEntity videosEntity = new VideosEntity();
                videosEntity.setCoverPath(coverPath);
                videosEntity.setStatus(StatusEnum.WAITING_REVIEW.code());
                videosEntity.setVideoHeight(target.getWorksHeight());
                videosEntity.setVideoPath(worksPath);
                videosEntity.setVideoSeconds(target.getWorksSeconds());
                videosEntity.setVideoWidth(target.getWorksWidth());
                videosEntity.setIsDeleted(DelEnum.NORMAL.code());
                videosService.save(videosEntity);
                worksEntity.setVideoId(videosEntity.getId());
            } else {
                ImagesEntity imagesEntity = new ImagesEntity();
                imagesEntity.setCoverPath(coverPath);
                imagesEntity.setStatus(StatusEnum.WAITING_REVIEW.code());
                imagesEntity.setImageHeight(target.getWorksHeight());
                imagesEntity.setImagePath(worksPath);
                imagesEntity.setImageSeconds(target.getWorksSeconds());
                imagesEntity.setImageWidth(target.getWorksWidth());
                imagesEntity.setIsDeleted(DelEnum.NORMAL.code());
                imagesService.save(imagesEntity);
                worksEntity.setImageId(imagesEntity.getId());
            }
            // 6.将作品数据存入数据库
            res = worksDao.insert(worksEntity);
            topicService.updateTopicAndWorksRelation(worksEntity.getId(), split);
            // 7. TODO 删除相对于缓存

            // 8.TODO 添加到ES中 目前还未设置后台 所以直接上传
            WorksEsModel worksEsModel = new WorksEsModel();
            BeanUtils.copyProperties(worksEntity, worksEsModel);
            topicIdStr.replace(";", " #");
            worksEsModel.setWorksDesc(worksEntity.getWorksDesc() + topicIdStr);
            searchFeignService.saveWorksEs(Arrays.asList(worksEsModel));
        } catch (Exception e) {
            // 如果抛出异常则会回滚事务 则需要删除文件  这个则调用
            // TODO 为了保证删除成功 则将删除操作发送到消息队列中实现
            e.printStackTrace();
        }
        return res > 0;
    }

    @Transactional
    @Override
    public boolean updateWorksById(MultipartFile file, String updateWorksJson) {
        // 1.需要先解析
        Gson gson = new Gson();
        UpdateWorksVO updateWorksVO = gson.fromJson(updateWorksJson, UpdateWorksVO.class);
        WorksEntity worksEntity = new WorksEntity();
        worksEntity.setId(updateWorksVO.getWorksId());
        // 2.如果是置顶则不需要其他操作
        if (updateWorksVO.isTop()) {
            worksEntity.setTop(updateWorksVO.isTop());
            int res = worksDao.updateById(worksEntity);
            return res > 0;
        }
        String coverPath = "";
        if (file != null) {
            ResultEntity<String> res = fileFeignService.uploadCloudFile(Arrays.asList(file));
            coverPath = res.getData();
        }
        worksEntity.setIsDeleted(updateWorksVO.getIsDeleted());
        worksEntity.setOpenDownload(updateWorksVO.getOpenDownload());
        worksEntity.setWorksDesc(updateWorksVO.getWorksDesc());
        worksEntity.setViewPermission(updateWorksVO.getViewPermission());
        if (updateWorksVO.getWorksType() == Video.getCode()) {
            VideosEntity videosEntity = new VideosEntity();
            videosEntity.setId(updateWorksVO.getVideosId());
            if (!"".equals(coverPath)) {
                videosEntity.setCoverPath(coverPath);
            }
            videosEntity.setIsDeleted(updateWorksVO.getIsDeleted());
            videosService.updateById(videosEntity);
        } else {
            ImagesEntity imagesEntity = new ImagesEntity();
            imagesEntity.setId(updateWorksVO.getImageId());
            if (!"".equals(coverPath)) {
                imagesEntity.setCoverPath(coverPath);
            }
            imagesEntity.setIsDeleted(updateWorksVO.getIsDeleted());
            imagesService.updateById(imagesEntity);
        }
        // 修改作品信息 还有判断是否和原来的一样
        int res = worksDao.updateById(worksEntity);
        // 判断是否需要修改Topic
        String topicIdsStr = updateWorksVO.getTopicTitles();
        if (StringUtils.isNotEmpty(topicIdsStr)) {
            String[] split = topicIdsStr.split(";");
            topicService.updateTopicAndWorksRelation(worksEntity.getId(), split);
        }
        // 修改ES的数据
        // 8.TODO 添加到ES中
        WorksEsModel worksEsModel = new WorksEsModel();
        WorksEntity worksEntity1 = worksDao.selectById(worksEntity.getId());
        BeanUtils.copyProperties(worksEntity1, worksEsModel);
        List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
        StringBuffer buffer = new StringBuffer();
        topicList.stream().forEach(item -> {buffer.append(" #"); buffer.append(item.getTopicTitle());});
        worksEsModel.setWorksDesc(worksEsModel.getWorksDesc() + buffer.toString());
        searchFeignService.saveWorksEs(Arrays.asList(worksEsModel));
        // 异步删除缓存
        return res > 0;
    }

    @Override
    public boolean statisticsWorksData() {
        // 1.获取所有用户信息
        List<UserDataInfo> userList = userFeignService.getUserIdList().getData();
        Map<Long, UserDataInfo> userMap = new HashMap<>();
        Long fansNum = 0L;
        // 需要统计粉丝数量则不用流
        for (UserDataInfo userDataInfo : userList) {
            userMap.put(userDataInfo.getUserId(), userDataInfo);
            fansNum += userDataInfo.getFansNum();
        }
        // 2.获取用户所有的作品信息
        List<Long> userIds = new ArrayList<>(userMap.keySet());
        Map<Long, WorksDataEntity> worksDataEntityMap = worksDao.selectWorksDataByUser(userIds,
                StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        // 生成Map好获取
        // 3.获取所有用户的数据
        WorksDataEntity worksDataEntity = worksDao.selectWorksData(
                StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        // 3.2.获取所有用户粉丝总数
        worksDataEntity.setOtherFansNum(fansNum);
        // 4.获取当天的开始时间
        String currentDayStartTime = DateUtils.getToDayStartTime();
        Date date = DateUtils.getDateFromStr(currentDayStartTime);
        Long userSize = Long.valueOf(userIds.size() == 0 ? 1 : userIds.size());
        List<WorksDataEntity> resList = userList.stream().map((item) -> {
            WorksDataEntity target = new WorksDataEntity();
            // 生成WorksDataEntity格式对象
            WorksDataEntity worksDataEntity1 = JSONObject.parseObject(JSONObject.toJSONString(worksDataEntityMap.get(item.getUserId())), WorksDataEntity.class);
            // 补全基本数据
            if (worksDataEntity1 == null) {
                worksDataEntity1 = new WorksDataEntity();
                worksDataEntity1.setPlayNum(0L);
                worksDataEntity1.setWorksNum(0L);
                worksDataEntity1.setWorksLikeNum(0L);
                worksDataEntity1.setWorksCollectNum(0L);
                worksDataEntity1.setWorksCommentNum(0L);
            }
            target.setWorksCommentNum(worksDataEntity1.getWorksCommentNum());
            target.setWorksCollectNum(worksDataEntity1.getWorksCollectNum());
            target.setWorksLikeNum(worksDataEntity1.getWorksLikeNum());
            target.setWorksNum(worksDataEntity1.getWorksNum());
            target.setPlayNum(worksDataEntity1.getPlayNum());
            // 补全用户信息
            UserDataInfo userDataInfo = userMap.get(item.getUserId());
            target.setUserId(item.getUserId());
            target.setCreateTime(date);
            target.setHomeVisitNum(userDataInfo.getHomeViewNum());
            target.setFansNum(userDataInfo.getFansNum());
            // 计算平均数
            target.setOtherCollectNum(worksDataEntity.getOtherCollectNum() / userSize);
            target.setOtherFansNum(worksDataEntity.getOtherFansNum() / userSize);
            target.setOtherLikeNum(worksDataEntity.getOtherLikeNum() / userSize);
            target.setOtherPlayNum(worksDataEntity.getOtherPlayNum() / userSize);
            target.setOtherWorksNum(worksDataEntity.getOtherWorksNum() / userSize);
            return target;
        }).collect(Collectors.toList());
        // 4.批量插入
        boolean res = worksDataService.insertBatchWorks(resList);
        return res;
    }

    @Override
    public List<WorksSimpleInfo> getCommentWorksList(Long userId) {
        // 1.校验是否为本人操作
//        UserDTO user = UserHolder.getUser();
//        if (user.getUserId() != userId) {
//            throw new ClientException(ErrorCode.CLIENT_ERROR);
//        }
        // 获取所有的文章文章数据
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        List<WorksEntity> worksList = worksDao.selectList(queryWrapper);
        List<WorksSimpleInfo> resList = new ArrayList<>();
        for (WorksEntity worksEntity : worksList) {
            WorksSimpleInfo target = new WorksSimpleInfo();
            target.setWorksId(worksEntity.getId());
            target.setWorksType(worksEntity.getWorksType());
            target.setCommentCounts(worksEntity.getCommentCounts());
            target.setUpdateTime(worksEntity.getUpdateTime());
            target.setWorksDesc(worksEntity.getWorksDesc());
            if (worksEntity.getWorksType() == Video.getCode()) {
                VideosEntity videosEntity = videosService.getById(worksEntity.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
            } else {
                ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
            }
            // 关联话题
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
            target.setTopicList(topicList);
            resList.add(target);
        }
        return resList;
    }

    @Override
    public WorksEntity getWorksInfoById(Long worksId) {
        return worksDao.selectById(worksId);
    }

    @Override
    public List<DiagnosisEntity> selectWorksDiagnosisByUser(List<Long> userIds, String startTime, String endTime, Integer status, Integer isDeleted) {
        return worksDao.selectWorksDiagnosisByUser(userIds, startTime, endTime, status, isDeleted);
    }

    @Override
    public ServeHomeInfo getWorksCoreTendency(Long userId, Integer period, Integer filedType) {
        ServeHomeInfo target = new ServeHomeInfo();
        // 1.作品数据（增加量）使用Redis来实现添加量 (默认是每日00:00更新)
        CompletableFuture<Void> serveHomeFuture = CompletableFuture.runAsync(() -> {
            // 默认是 period 天的间隔 更新数据
            ServeHomeInfo data = worksDataService.getWorksDataByDay(userId, period);
            BeanUtils.copyProperties(data, target, "twoWeekFiledWorksMap");
        }, executor);

        // 2.两周的上传作品量折线图
        CompletableFuture<Void> uploadWorksFuture = CompletableFuture.runAsync(() -> {
            Map<String, Object> worksMap = getTwoWeekFiledWorks(userId, period, filedType);
            target.setTwoWeekFiledWorksMap(worksMap);
        }, executor);
        // 等待所有任务完成
        try {
            CompletableFuture.allOf(serveHomeFuture, uploadWorksFuture).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return target;
    }

    @Override
    public List<WorksSummaryVO> getWorksSummaryList(Long userId) {
        // 要求：播放量最高、点赞最高、收藏最高、评论最高
        // 1.获取近30天的时间
        String currentTime = DateUtils.getToDayStartTime();
        Date preDaysDate = DateUtils.getDate(currentTime, -29);
        String perDateTime = DateUtils.getOneDayStartTime(preDaysDate);
        // 2.数据库操作 获取ID 分别获取这些的最高值
        Map<String, WorksEntity> map = new HashMap<>();
        // 2.1、播放量最高
        CompletableFuture<Void> playNumFuture = CompletableFuture.runAsync(() -> {
            WorksEntity playWorks = getFileMaxNum("play_counts", userId);
            map.put("play_counts", playWorks);
        }, executor);
        // 2.2、点赞最高
        CompletableFuture<Void> likeNumFuture = CompletableFuture.runAsync(() -> {
            WorksEntity likeWorks = getFileMaxNum("like_counts", userId);
            map.put("like_counts", likeWorks);
        }, executor);
        // 2.3、收藏最高
        CompletableFuture<Void> collectNumFuture = CompletableFuture.runAsync(() -> {
            WorksEntity collectWorks = getFileMaxNum("collect_counts", userId);
            map.put("collect_counts", collectWorks);
        }, executor);
        // 2.4、评论最高
        CompletableFuture<Void> commentNumFuture = CompletableFuture.runAsync(() -> {
            WorksEntity commentWorks = getFileMaxNum("comment_counts", userId);
            map.put("comment_counts", commentWorks);
        }, executor);
        // 等待所有任务完成
        try {
            CompletableFuture.allOf(playNumFuture, likeNumFuture, collectNumFuture, commentNumFuture).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 3.融合数据 判断是否存在重复的数据
        Map<Long, List<String>> labelMap = new HashMap<>();
        Iterator<Map.Entry<String, WorksEntity>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, WorksEntity> entry = iterator.next();
            if (labelMap.containsKey(entry.getValue().getId())) {
                labelMap.get(entry.getValue().getId()).add(entry.getKey());
            } else {
                List<String> list = new ArrayList<>();
                list.add(entry.getKey());
                labelMap.put(entry.getValue().getId(), list);
            }
        }
        List<WorksSummaryVO> resList = new ArrayList<>();
        // 将Map的数据进行分类
        labelMap.keySet().stream().forEach(item -> {
            WorksEntity worksEntity = map.get(labelMap.get(item).get(0));
            WorksSummaryVO target = new WorksSummaryVO();
            if (worksEntity.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
            } else {
                VideosEntity videosEntity = videosService.getById(worksEntity.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
            }
            target.setWorksId(worksEntity.getId());
            target.setCollectCounts(worksEntity.getCollectCounts());
            target.setCommentCounts(worksEntity.getCommentCounts());
            target.setLikeCounts(worksEntity.getLikeCounts());
            target.setPlayCounts(worksEntity.getPlayCounts());
            target.setUpdateTime(worksEntity.getUpdateTime());
            target.setWorksDesc(worksEntity.getWorksDesc());
            target.setWorksType(worksEntity.getWorksType());
            target.setLabelList(labelMap.get(item));
            // 获取标签信息
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
            target.setTopicList(topicList);
            resList.add(target);
        });
        return resList;
    }

    @Override
    public List<WorksCartVO> getWorksCartList(Long userId) {
        // 1.获取Works基本信息
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.ne("status", StatusEnum.FORBIDDEN.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        List<WorksEntity> worksList = worksDao.selectList(queryWrapper);
        // 2.渲染基本信息
        List<WorksCartVO> resList = worksList.stream().map(item -> {
            WorksCartVO target = new WorksCartVO();
            // 渲染基本信息
            target.setWorksId(item.getId());
            target.setCollectCounts(item.getCollectCounts());
            target.setCommentCounts(item.getCommentCounts());
            target.setLikeCounts(item.getLikeCounts());
            target.setPlayCounts(item.getPlayCounts());
            target.setStatus(item.getStatus());
            target.setUpdateTime(item.getUpdateTime());
            target.setWorksDesc(item.getWorksDesc());
            target.setWorksType(item.getWorksType());
            // 渲染其他信息
            if (item.getWorksType() == Video.getCode()) {
                VideosEntity videosEntity = videosService.getById(item.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
            } else {
                ImagesEntity imagesEntity = imagesService.getById(item.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
            }
            // 渲染指数  如果播放量为0 则直接赋值
            if (item.getPlayCounts() == 0) {
                target.setCollectExponent(0.0);
                target.setLikeExponent(0.0);
                target.setCommentExponent(0.0);
            } else {
                target.setCollectExponent(Double.parseDouble(String.format("%.2f", item.getCollectCounts() / Double.valueOf(item.getPlayCounts()) * 100)));
                target.setLikeExponent(Double.parseDouble(String.format("%.2f", item.getLikeCounts() / Double.valueOf(item.getPlayCounts()) * 100)));
                target.setCommentExponent(Double.parseDouble(String.format("%.2f", item.getCommentCounts() / Double.valueOf(item.getPlayCounts()) * 100)));
            }
            // 获取标签信息
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(item.getId());
            target.setTopicList(topicList);
            return target;
        }).collect(Collectors.toList());
        return resList;
    }

    @Override
    public WeekReportVO getWeekReportInfo(Long userId) {
        WeekReportVO target = new WeekReportVO();
        // 1.获取上一周的时间
        String preWeekStartTime = DateUtils.getLastWeekStartTimeStr();
        // 2.通过userId 和 preWeekStartTime 来获取周报
        WeekReportEntity weekReportEntity = weekReportService.queryWeekReportInfo(userId, preWeekStartTime);
        BeanUtils.copyProperties(weekReportEntity, target);
        // 3.通过作品ID获取作品的信息
        // 3.1.获取上周的作品信息
        WorksEntity weekWorksInfo = worksDao.selectById(weekReportEntity.getWeekWorksId());
        WorksListInfo weekWorksListInfo = getWorksListInfo(weekWorksInfo);
        target.setWeekReportWorks(weekWorksListInfo);
        // 3.2.获取全局的作品信息
        WorksEntity allWorksInfo = worksDao.selectById(weekReportEntity.getAllWorksId());
        WorksListInfo allWorksListInfo = getWorksListInfo(allWorksInfo);
        target.setAllReportWorks(allWorksListInfo);
        return target;
    }

    @Override
    public boolean createWeekReportInfo() {
        // 1.获取用户信息  获取本周已经发布作品的用户
        // 1.获取周期
        String lastWeekStartTime = DateUtils.getLastWeekStartTimeStr();
        // 上周的最后一天
        String lastWeekEndTime = DateUtils.getLastWeekEndTimeStr();
        List<Long> userIds = worksDao.getUserIdByWorksActive(lastWeekStartTime, lastWeekEndTime,
                StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        userIds.stream().forEach(item -> {
            weekReportService.createWeekReportInfo(item);
        });
        return true;
    }

    @Override
    public WorksEntity getWorksBestInfoByTime(Long userId, String lastWeekStartTime, String lastWeekEndTime) {
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        if (StringUtils.isNotEmpty(lastWeekEndTime)) {
            queryWrapper.ge("create_time", lastWeekStartTime);
            queryWrapper.lt("create_time", lastWeekEndTime);
        }
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.orderByDesc("play_counts").orderByDesc("like_counts");
        queryWrapper.last("LIMIT 1");
        return worksDao.selectOne(queryWrapper);
    }

    @Override
    public SimpleWorksTO getWorksSimpleInfo(Long worksId) {
        SimpleWorksTO target = new SimpleWorksTO();
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", worksId);
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        WorksEntity works = worksDao.selectOne(queryWrapper);
        if (works == null) return null;
        if (works.getWorksType() == Video.getCode()) {
            VideosEntity videosEntity = videosService.getById(works.getVideoId());
            target.setCoverPath(videosEntity.getCoverPath());
        } else {
            ImagesEntity imagesEntity = imagesService.getById(works.getImageId());
            target.setCoverPath(imagesEntity.getCoverPath());
        }
        target.setWorksId(works.getId());
        return target;
    }

    @Override
    public boolean createRecommendList(Long userId) {
        // 先删除上次的数据
        worksDao.deleteRecommendByUserId(userId);
        List<Long> recommendTopicIdList = recommend.recommend(userId);
        // 2.获取所有的标题
        List<String> topicTitleList = topicService.queryTopicTitleByIds(recommendTopicIdList);
        SearchParamTO target = new SearchParamTO();
        target.setIndexType(0);
        target.setTopicTopicList(topicTitleList);
        target.setSearchSource("推荐列表");
        target.setUserId(userId);
        List<Long> worksIds = searchFeignService.searchRecommend(target).getData();
        if (worksIds == null || worksIds.size() == 0)return false;
        // 将ID 通过 ; 拼接存储
        StringBuilder sb = new StringBuilder();
        Iterator<Long> iterator = recommendTopicIdList.iterator();
        while (iterator.hasNext()) {
            sb.append(iterator.next());
            if (iterator.hasNext()) {
                sb.append(";");
            }
        }
        StringBuilder sb2 = new StringBuilder();
        Iterator<Long> iterator2 = worksIds.iterator();
        while (iterator2.hasNext()) {
            sb2.append(iterator2.next());
            if (iterator2.hasNext()) {
                sb2.append(";");
            }
        }
        // 存储到数据库中
        return worksDao.saveRecommendTopic(userId, sb.toString(), sb2.toString());
    }

    @Override
    public List<WorksVO> getRecommendList(Long userId, Integer page) {
        // 1.获取所有的作品的ID
        String worksIds = worksDao.getWorksIdsByUserId(userId);
        List<Long> worksIdList = Arrays.asList(worksIds.split(";")).stream().map(item -> {
            return Long.parseLong(item);
        }).collect(Collectors.toList());
        // 2.分页查询
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.in("id", worksIdList);
        queryWrapper.last("LIMIT " + pageSize * (page - 1) + "," + pageSize);
        List<WorksEntity> worksEntities = worksDao.selectList(queryWrapper);
        return getWorksVOList(worksEntities);
    }

    private List<WorksVO> getWorksVOList(List<WorksEntity> worksEntities) {
        List<WorksVO> resList = worksEntities.stream().map(item -> {
            WorksVO target = new WorksVO();
            target.setWorksId(item.getId());
            BeanUtils.copyProperties(item, target);
            // 1.1.判断为视频还是图片
            CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
                if (item.getWorksType() == Video.getCode()) {
                    VideosEntity videosEntity = videosService.getById(item.getVideoId());
                    target.setCoverPath(videosEntity.getCoverPath());
                    target.setVideoPath(videosEntity.getVideoPath());
                    target.setWorksSeconds(videosEntity.getVideoSeconds());
                    target.setWorksWidth(videosEntity.getVideoWidth());
                    target.setWorksHeight(videosEntity.getVideoHeight());
                } else {
                    ImagesEntity imagesEntity = imagesService.getById(item.getImageId());
                    target.setCoverPath(imagesEntity.getCoverPath());
                    // 分隔数据
                    String[] split = imagesEntity.getImagePath().split(";");
                    target.setImageList(Arrays.asList(split));
                    target.setWorksSeconds(imagesEntity.getImageSeconds());
                    target.setWorksWidth(imagesEntity.getImageWidth());
                    target.setWorksHeight(imagesEntity.getImageHeight());
                }
            }, executor);

            // 1.2.判断是否存在音频
            CompletableFuture<Void> audioFuture = CompletableFuture.runAsync(() -> {
                if (item.getAudioId() != null) {
                    AudioEntity audioEntity = audioService.queryAudioById(item.getAudioId());
                    target.setAudioAuthorName(audioEntity.getAuthor());
                    target.setAudioName(audioEntity.getAudioName());
                    target.setAudioPath(audioEntity.getAudioPath());
                    target.setAudioSeconds(audioEntity.getAudioSeconds());
                }
            }, executor);

            // 1.3.判断是否存在商品
            CompletableFuture<Void> productFuture = CompletableFuture.runAsync(() -> {
                if (item.getProductId() != null) {
                    // TODO 作品信息还未实现
                }
            }, executor);

            // 1.4.判断是否存在广告
            CompletableFuture<Void> advertFuture = CompletableFuture.runAsync(() -> {
                if (item.getAdvertId() != null) {
                    AdvertTO advert = systemFeignService.getAdvertInfo(item.getAdvertId()).getData();
                    target.setAdvertId(advert.getId());
                    target.setAdvertName(advert.getAdvertName());
                }
            }, executor);

            // 1.5.添加话题
            CompletableFuture<Void> topicFuture = CompletableFuture.runAsync(() -> {
                List<TopicInfoVO> topicList = topicService.queryWorksTopicList(item.getId());
                target.setTopicList(topicList);
            }, executor);

            // 等待所有任务完成
            try {
                CompletableFuture.allOf(imageFuture, audioFuture, advertFuture, productFuture, topicFuture).get();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return target;
        }).collect(Collectors.toList());
        return resList;
    }

    @Override
    public List<WorksSimpleInfo> getHomeList(Long userId) {
        // 1.在不同的流量池中随机获取权重的ID列表
        // 1.1.判断缓存中是否存在数据
        List<Long> worksIdList = distributedCache.get(RedisConstants.HOME_WORKS_LIST + Constant.SYMBOL_COLON + userId, List.class);
        if (worksIdList == null || worksIdList.size() == 0) {
            // 1.2.需要查询获取作品列表数据
            List<WorksEntity> worksList = new ArrayList<>();
            // 查询数据库总记录
            long count = this.count();
            double[] rate = new double[]{0.1, 0.15, 0.2, 0.25, 0.3};
            for (int i = 1; i <= 5; i++) {
                // 随机数起始位置
                int randomCount = (int) (Math.random() * count);
                QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
                queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
                queryWrapper.eq("grade", i);
                queryWrapper.orderByDesc("id");
                queryWrapper.last("LIMIT " + randomCount + "," + (int) (pageSize * 6 * rate[i - 1]));
                List<WorksEntity> worksEntities = worksDao.selectList(queryWrapper);
                worksList.addAll(worksEntities);
            }
            // 需要将数据打乱
            worksList.sort((t1, t2) -> t2.getCreateTime().compareTo(t1.getCreateTime()));
            worksIdList = worksList.stream().map(item -> {
                return item.getId();
            }).collect(Collectors.toList());
        }
        List<Long> worksIds;
        // 1.3.截取指定30条数据再存入到Redis中
        if (worksIdList.size() > pageSize) {
            worksIds = worksIdList.subList(pageSize, worksIdList.size());
        } else {
            worksIds = new ArrayList<>();
        }
        // 需要用JSON字符串封装
        distributedCache.put(RedisConstants.HOME_WORKS_LIST + Constant.SYMBOL_COLON + userId, worksIds, 1, TimeUnit.DAYS);
        // 2.通过ID获取指定作品信息
        List<Long> worksId = worksIdList.subList(0, worksIdList.size() >= pageSize ? pageSize : worksIdList.size());
        List<WorksSimpleInfo> resList = worksId.stream().map(item -> {
            WorksSimpleInfo target = new WorksSimpleInfo();
            WorksEntity worksEntity = worksDao.selectById(item);
            target.setWorksId(item);
            BeanUtils.copyProperties(item, target);
            if (worksEntity.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
                target.setWorksSeconds(imagesEntity.getImageSeconds());
            } else {
                VideosEntity videosEntity = videosService.getById(worksEntity.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
                target.setWorksSeconds(videosEntity.getVideoSeconds());
            }
            // 获取标签信息
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
            target.setTopicList(topicList);
            return target;
        }).collect(Collectors.toList());
        return resList;
    }

    @Override
    public List<WorksVO> getFollowList(Long userId) {
        // 1.获取一周内用户关注的列表
        // 获取缓存
        List<Long> alreadyWorksIds = distributedCache.get(RedisConstants.ALREADY_FOLLOW_WORKS_LIST + Constant.SYMBOL_COLON + userId, List.class);
        // 1.1.获取所有关注对象
        List<Long> followIdList = userFeignService.getUserFollowList(userId).getData();
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.in("user_id", followIdList);
        if (alreadyWorksIds != null && alreadyWorksIds.size() != 0) {
            queryWrapper.notIn("id", alreadyWorksIds);
        } else {
            alreadyWorksIds = new ArrayList<>();
        }
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("LIMIT 20");
        List<WorksEntity> worksEntities = worksDao.selectList(queryWrapper);
        // 2.获取最近
        List<WorksVO> resList = getWorksVOList(worksEntities);
        // 3.排序
        Collections.sort(resList, new Comparator<WorksVO>() {
            @Override
            public int compare(WorksVO p1, WorksVO p2) {
                return (int) (p2.getLikeCounts() / p2.getPlayCounts() - p1.getLikeCounts() / p1.getPlayCounts());
            }
        });
        // 将数据存入到Redis
        List<Long> collect = worksEntities.stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());
        alreadyWorksIds.addAll(collect);
        // 存入到Redis中
        distributedCache.put(RedisConstants.ALREADY_FOLLOW_WORKS_LIST + Constant.SYMBOL_COLON + userId, alreadyWorksIds);
        return resList;
    }

    @Override
    public List<WorksVO> getFriendList(Long userId) {
        // 获取缓存
        List<Long> alreadyWorksIds = distributedCache.get(RedisConstants.ALREADY_FRIEND_WORKS_LIST + Constant.SYMBOL_COLON + userId, List.class);
        // 1.1.获取所有关注对象
        List<Long> friendIdList = userFeignService.getUserFriendList(userId).getData();
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.in("user_id", friendIdList);
        if (alreadyWorksIds != null && alreadyWorksIds.size() != 0) {
            queryWrapper.notIn("id", alreadyWorksIds);
        } else {
            alreadyWorksIds = new ArrayList<>();
        }
        queryWrapper.orderByDesc("create_time");
        queryWrapper.last("LIMIT 10");
        List<WorksEntity> worksEntities = worksDao.selectList(queryWrapper);
        // 2.获取最近
        List<WorksVO> resList = getWorksVOList(worksEntities);
        // 3.排序
        Collections.sort(resList, new Comparator<WorksVO>() {
            @Override
            public int compare(WorksVO p1, WorksVO p2) {
                return (int) (p2.getLikeCounts() / p2.getPlayCounts() - p1.getLikeCounts() / p1.getPlayCounts());
            }
        });
        // 将数据存入到Redis
        List<Long> collect = worksEntities.stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());
        alreadyWorksIds.addAll(collect);
        // 存入到Redis中
        distributedCache.put(RedisConstants.ALREADY_FRIEND_WORKS_LIST + Constant.SYMBOL_COLON + userId, alreadyWorksIds);
        return resList;
    }

    @Override
    public List<WorksSimpleInfo> getHotWorksList(Long userId) {
        // 获取缓存 设置有效期 2
        List<Long> alreadyWorksIds = distributedCache.get(RedisConstants.ALREADY_HOT_WORKS_LIST + Constant.SYMBOL_COLON + userId,
                List.class);
        // 1.1.根据播放量来获取热点数据 （最近一周的数据）
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.ge("create_time", DateUtils.getPastDate(7, DateUtils.FORMAT_STRING));
        if (alreadyWorksIds != null && alreadyWorksIds.size() != 0) {
            queryWrapper.notIn("id", alreadyWorksIds);
        } else {
            alreadyWorksIds = new ArrayList<>();
        }
        queryWrapper.orderByDesc("play_counts");
        queryWrapper.last("LIMIT 30");
        List<WorksEntity> worksEntities = worksDao.selectList(queryWrapper);
        // 2.获取最近
        List<WorksSimpleInfo> resList = worksEntities.stream().map(item -> {
            WorksSimpleInfo target = new WorksSimpleInfo();
            target.setWorksId(item.getId());
            BeanUtils.copyProperties(item, target);
            if (item.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(item.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
                target.setWorksSeconds(imagesEntity.getImageSeconds());
            } else {
                VideosEntity videosEntity = videosService.getById(item.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
                target.setWorksSeconds(videosEntity.getVideoSeconds());
            }
            // 获取标签信息
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(item.getId());
            target.setTopicList(topicList);
            return target;
        }).collect(Collectors.toList());
        // 3.排序
        Collections.sort(resList, new Comparator<WorksSimpleInfo>() {
            @Override
            public int compare(WorksSimpleInfo p1, WorksSimpleInfo p2) {
                return (int) (p2.getLikeCounts() / p2.getPlayCounts() - p1.getLikeCounts() / p1.getPlayCounts());
            }
        });
        // 将数据存入到Redis
        List<Long> collect = worksEntities.stream().map(item -> {
            return item.getId();
        }).collect(Collectors.toList());
        alreadyWorksIds.addAll(collect);
        // 存入到Redis中
        distributedCache.put(RedisConstants.ALREADY_HOT_WORKS_LIST + Constant.SYMBOL_COLON + userId, alreadyWorksIds);
        return resList;
    }

    @Override
    public List<WorksSimpleInfo> getTypeWorksList(Long userId, Long typeId) {
        // 1.根据流量池的等级划分来实现
        List<Long> alreadyWorksIds = distributedCache.get(RedisConstants.ALREADY_HOT_WORKS_LIST +
                Constant.SYMBOL_COLON + userId + Constant.SYMBOL_COLON + typeId, List.class);
        // 1.2.需要查询获取作品列表数据
        List<WorksEntity> worksList = new ArrayList<>();
        // 获取指定类型数据的
        Long count = worksDao.queryWorksCountByTypeId(typeId);
        double[] rate = new double[]{0.1, 0.15, 0.2, 0.25, 0.3};
        for (int i = 1; i <= 5; i++) {
            // 随机数起始位置
            int randomCount = (int) (Math.random() * count);
            List<WorksEntity> worksEntities = worksDao.queryTypeWorksList(StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code(),
                    i, typeId, DateUtils.getPastDate(14, DateUtils.YYYY_MM_DD_HH_MM_SS),
                    alreadyWorksIds, randomCount, (int) (20 * rate[i - 1]));
            worksList.addAll(worksEntities);
            if (worksEntities == null || worksEntities != null && worksEntities.size() == 0) {
                List<WorksEntity> worksEntities1 = worksDao.queryTypeWorksList(StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code(),
                        i, typeId, null,
                        alreadyWorksIds, randomCount, (int) (20 * rate[i - 1]));
                worksList.addAll(worksEntities1);
            }
        }
        List<Long> worksIds = new ArrayList<>();
        // 需要将数据打乱
        List<WorksSimpleInfo> resList = worksList.stream().map(item -> {
            WorksSimpleInfo target = new WorksSimpleInfo();
            target.setWorksId(item.getId());
            BeanUtils.copyProperties(item, target);
            if (item.getWorksType() == Image.getCode()) {
                ImagesEntity imagesEntity = imagesService.getById(item.getImageId());
                target.setCoverPath(imagesEntity.getCoverPath());
                target.setWorksSeconds(imagesEntity.getImageSeconds());
            } else {
                VideosEntity videosEntity = videosService.getById(item.getVideoId());
                target.setCoverPath(videosEntity.getCoverPath());
                target.setWorksSeconds(videosEntity.getVideoSeconds());
            }
            // 获取标签信息
            List<TopicInfoVO> topicList = topicService.queryWorksTopicList(item.getId());
            target.setTopicList(topicList);
            worksIds.add(item.getId());
            return target;
        }).collect(Collectors.toList());
        if (alreadyWorksIds == null) {
            alreadyWorksIds = new ArrayList<>();
        }
        alreadyWorksIds.addAll(worksIds);
        // 存储到数据库中 TODO 使用了NOT IN 出现查询慢
        distributedCache.put(RedisConstants.ALREADY_HOT_WORKS_LIST +
                Constant.SYMBOL_COLON + userId + Constant.SYMBOL_COLON + typeId, alreadyWorksIds);
        return resList;
    }

    @Override
    public List<WorksVO> getRandomWorksList() {
        // 获取当前正常使用的作品数量
        long count = this.count();
        // 随机数起始位置
        int randomCount = (int) (Math.random() * count);
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.last("LIMIT " + randomCount + "," + recommendPageSize);
        return getWorksVOList(worksDao.selectList(queryWrapper));
    }

    @Override
    public void updateWorksCommentNum(Long worksId, Integer num) {
        worksDao.updateWorksCommentNum(worksId, num);
    }

    @Override
    public boolean worksLikeById(Long worksId, Long userId) {
        return likeService.worksLikeById(worksId, userId);
    }

    @Override
    public boolean worksUnlikeById(Long worksId, Long userId) {
        return likeService.worksUnlikeById(worksId, userId);
    }

    @Override
    public boolean worksCollectById(Long worksId, Long userId) {
        return collectService.worksCollectById(worksId, userId);
    }

    @Override
    public boolean worksCancelCollectById(Long worksId, Long userId) {
        return collectService.worksCancelCollectById(worksId, userId);
    }

    @Override
    public boolean saveWorksProductId(Long worksId, Long productId) {
        WorksEntity target = new WorksEntity();
        target.setId(worksId);
        target.setProductId(productId);
        return worksDao.updateById(target) > 0;
    }

    @Override
    public boolean deleteWorksProductId(Long worksId) {
        WorksEntity worksEntity = new WorksEntity();
        worksEntity.setId(worksId);
        worksEntity.setProductId(null);
        return worksDao.updateById(worksEntity) > 0;
    }

    @Override
    public boolean saveWorksAdvertId(Long worksId, Long advertId) {
        WorksEntity target = new WorksEntity();
        target.setId(worksId);
        target.setAdvertId(advertId);
        return worksDao.updateById(target) > 0;
    }

    @Override
    public boolean deleteWorksAdvertId(Long worksId) {
        WorksEntity worksEntity = new WorksEntity();
        worksEntity.setId(worksId);
        worksEntity.setAdvertId(null);
        return worksDao.updateById(worksEntity) > 0;
    }

    @Override
    public List<WorksSimpleInfo> getSimpleRandomWorksList() {
        // 获取当前正常使用的作品数量
        long count = this.count();
        // 随机数起始位置
        int randomCount = (int) (Math.random() * count);
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.last("LIMIT " + randomCount + "," + recommendPageSize);
        return getSimpleWorksList(worksDao.selectList(queryWrapper));
    }

    private List<WorksSimpleInfo> getSimpleWorksList(List<WorksEntity> worksEntities) {
        List<WorksSimpleInfo> resList = worksEntities.stream().map(item -> {
            WorksSimpleInfo target = new WorksSimpleInfo();
            target.setWorksId(item.getId());
            BeanUtils.copyProperties(item, target);
            // 1.1.判断为视频还是图片
            CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
                if (item.getWorksType() == Video.getCode()) {
                    VideosEntity videosEntity = videosService.getById(item.getVideoId());
                    target.setCoverPath(videosEntity.getCoverPath());
                    target.setWorksSeconds(videosEntity.getVideoSeconds());
                    target.setWorksWidth(videosEntity.getVideoWidth());
                    target.setWorksHeight(videosEntity.getVideoHeight());
                } else {
                    ImagesEntity imagesEntity = imagesService.getById(item.getImageId());
                    target.setCoverPath(imagesEntity.getCoverPath());
                    target.setWorksSeconds(imagesEntity.getImageSeconds());
                    target.setWorksWidth(imagesEntity.getImageWidth());
                    target.setWorksHeight(imagesEntity.getImageHeight());
                }
            }, executor);

            // 1.2.添加话题
            CompletableFuture<Void> topicFuture = CompletableFuture.runAsync(() -> {
                List<TopicInfoVO> topicList = topicService.queryWorksTopicList(item.getId());
                target.setTopicList(topicList);
            }, executor);

            // 等待所有任务完成
            try {
                CompletableFuture.allOf(imageFuture, topicFuture).get();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return target;
        }).collect(Collectors.toList());
        return resList;
    }

    private WorksListInfo getWorksListInfo(WorksEntity worksEntity) {
        WorksListInfo weekWorksListInfo = new WorksListInfo();
        weekWorksListInfo.setWorksId(worksEntity.getId());
        weekWorksListInfo.setWorksDesc(worksEntity.getWorksDesc());
        weekWorksListInfo.setUpdateTime(worksEntity.getUpdateTime());
        weekWorksListInfo.setStatus(worksEntity.getStatus());
        weekWorksListInfo.setCommentCounts(worksEntity.getCommentCounts());
        weekWorksListInfo.setCollectCounts(worksEntity.getCollectCounts());
        weekWorksListInfo.setLikeCounts(worksEntity.getLikeCounts());
        weekWorksListInfo.setWorksType(worksEntity.getWorksType());
        // 渲染其他信息
        if (weekWorksListInfo.getWorksType() == Video.getCode()) {
            VideosEntity videosEntity = videosService.getById(worksEntity.getVideoId());
            weekWorksListInfo.setCoverPath(videosEntity.getCoverPath());
        } else {
            ImagesEntity imagesEntity = imagesService.getById(worksEntity.getImageId());
            weekWorksListInfo.setCoverPath(imagesEntity.getCoverPath());
        }
        // 获取标签信息
        List<TopicInfoVO> topicList = topicService.queryWorksTopicList(worksEntity.getId());
        weekWorksListInfo.setTopicList(topicList);
        return weekWorksListInfo;
    }

    public static void main(String[] args) {
        System.out.println(DateUtils.getLastWeekEndTimeStr());
    }

    /**
     * 通过字段名和用户名获取最大的数据
     *
     * @param filed
     * @param userId
     * @return
     */
    public WorksEntity getFileMaxNum(String filed, Long userId) {
        QueryWrapper<WorksEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("status", StatusEnum.NORMAL_USE.code());
        queryWrapper.eq("is_deleted", DelEnum.NORMAL.code());
        queryWrapper.orderByDesc(filed);
        queryWrapper.last("LIMIT 1");
        return worksDao.selectOne(queryWrapper);
    }

    /**
     * 获取用户参数获取折线图
     *
     * @param userId
     * @return
     */
    private Map<String, Object> getTwoWeekFiledWorks(Long userId, Integer period, Integer filedType) {
        // 1.查看缓存是否命中
        String weekVisitJson = distributedCache.get(RedisConstants.SERVE_PREFIX +
                Constant.SYMBOL_COLON + RedisConstants.PERIOD_CORE_TENDENCY_WORKS + Constant.SYMBOL_COLON + filedType + "_" + userId, String.class);
        if (StringUtils.isNotEmpty(weekVisitJson)) {
            Map<String, Object> weekVisitMap = JsonUtils.jsonToMap(weekVisitJson);
            return weekVisitMap;
        }

        // 2.数据库获取数据
        // 获取到今天结束的时间
        String startTime = DateUtils.getToDayStartTime();
        // 获取最近period天的日期
        if (period < 7) period = 7;
        Date sevenDaysDate = DateUtils.getDate(startTime, -period);
        String perDateTime = DateUtils.getOneDayStartTime(sevenDaysDate);
        // 获取最近period天的数组列表
        List<String> sevenDaysList = DateUtils.getDaysByN(period, "yyyy-MM-dd");
        // 获得最近period天的filedType数量
        List<WorksDataSimpleVO> worksDataList = worksDataService.getWorksCoreTendency(userId,
                Constant.FiledType.getInfoByCode(filedType), perDateTime, startTime);
        Map<String, Object> countWorksMap = new HashMap<>();
        // 需要对数据进行处理  后者 - 前者的num
        for (int i = 1; i < worksDataList.size(); i++) {
            worksDataList.get(i).setNum(worksDataList.get(i).getNum() - worksDataList.get(i - 1).getNum());
        }
        for (WorksDataSimpleVO item : worksDataList) {
            countWorksMap.put(item.getDate(), item.getNum());
        }
        // 访问量数组
        List<Integer> worksList = new ArrayList<>();

        for (String day : sevenDaysList) {
            if (countWorksMap.get(day) != null) {
                Number pvNumber = (Number) countWorksMap.get(day);
                worksList.add(pvNumber.intValue());
            } else {
                worksList.add(0);
            }
        }

        Map<String, Object> resultMap = new HashMap<>(period);
        // 不含年份的数组格式
        List<String> resultSevenDaysList = DateUtils.getDaysByN(period,
                "MM-dd");
        resultMap.put("date", resultSevenDaysList);
        // filedType
        resultMap.put("wv", worksList);

        // 3.异步添加数据到缓存中
        // TODO 可能会存在短期的数据不一致的问题，即零点时不能准时更新，而是要在0:10才会重新刷新纪录。 后期考虑加入定时器处理这个问题
        // 将filedType传存入Redis中【过期时间30分钟】
//        CompletableFuture.runAsync(() -> {
//            // 异步将数据存入缓存中
//            distributedCache.put(RedisConstants.SERVE_PREFIX +
//                    Constant.SYMBOL_COLON + RedisConstants.PERIOD_CORE_TENDENCY_WORKS + Constant.SYMBOL_COLON + filedType + "_" + userId, JsonUtils.objectToJson(resultMap), 30, TimeUnit.MINUTES);
//        }, executor);
        return resultMap;
    }

    /**
     * 获取用户最近两周的作品上传数量
     *
     * @param userId
     * @return
     */
    private Map<String, Object> getTwoWeekUploadWorks(Long userId) {
        // 1.查看缓存是否命中
        String weekVisitJson = distributedCache.get(RedisConstants.SERVE_PREFIX +
                Constant.SYMBOL_COLON + RedisConstants.TWO_WEEK_UPLOAD_WORKS + Constant.SYMBOL_COLON + userId, String.class);
        if (StringUtils.isNotEmpty(weekVisitJson)) {
            Map<String, Object> weekVisitMap = JsonUtils.jsonToMap(weekVisitJson);
            return weekVisitMap;
        }
        // 2.数据库获取数据
        // 获取到今天结束的时间
        String todayEndTime = DateUtils.getToDayEndTime();
        //获取最近14天的日期
        Date sevenDaysDate = DateUtils.getDate(todayEndTime, -13);
        String sevenDays = DateUtils.getOneDayStartTime(sevenDaysDate);
        // 获取最近14天的数组列表
        List<String> sevenDaysList = DateUtils.getDaysByN(14, "yyyy-MM-dd");
        // 获得最近14天的作品上传数量
        List<Map<String, Object>> worksMap = worksDao.getWorksByTwoWeek(userId, sevenDays, todayEndTime,
                StatusEnum.NORMAL_USE.code(), DelEnum.NORMAL.code());
        Map<String, Object> countWorksMap = new HashMap<>();

        for (Map<String, Object> item : worksMap) {
            countWorksMap.put(item.get("DATE").toString(), item.get("COUNT"));
        }
        // 访问量数组
        List<Integer> worksList = new ArrayList<>();

        for (String day : sevenDaysList) {
            if (countWorksMap.get(day) != null) {
                Number pvNumber = (Number) countWorksMap.get(day);
                worksList.add(pvNumber.intValue());
            } else {
                worksList.add(0);
            }
        }
        Map<String, Object> resultMap = new HashMap<>(Constant.NUM_TWO);
        // 不含年份的数组格式
        List<String> resultSevenDaysList = DateUtils.getDaysByN(14,
                "MM-dd");
        resultMap.put("date", resultSevenDaysList);
        // 作品数量
        resultMap.put("wv", worksList);

        // 3.异步添加数据到缓存中
        // TODO 可能会存在短期的数据不一致的问题，即零点时不能准时更新，而是要在0:10才会重新刷新纪录。 后期考虑加入定时器处理这个问题
        // 将两周作品上传存入Redis中【过期时间30分钟】
        CompletableFuture.runAsync(() -> {
            // 异步将数据存入缓存中
            distributedCache.put(RedisConstants.SERVE_PREFIX +
                    Constant.SYMBOL_COLON + RedisConstants.TWO_WEEK_UPLOAD_WORKS + Constant.SYMBOL_COLON + userId, JsonUtils.objectToJson(resultMap), 30, TimeUnit.MINUTES);
        }, executor);
        return resultMap;
    }


}